#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <string>
#include <json-c/json_object.h> // json
#include "stdShared.h"

using namespace std;

// 服务端口
#define SERVER_PORT 8080
#define USERINFO_SIZE 20
#define BUFFER_SIZE 128

void signUpLoginInterFace()
{
    cout << "1、注册" << endl;
    cout << "2、登录" << endl;
}

// 定义用户信息结构体
struct userInfo
{
    int type; // 1：注册  2：登录
    char name[USERINFO_SIZE];
    char passwd[USERINFO_SIZE];
};

// 注册信息
void registerInfo(int sockfd)
{
    string username;
    cout << "请输入你的姓名：" << endl;
    cin >> username;

    string passwd;
    cout << "请输入你的密码：" << endl;
    cin >> passwd;

#if 0
    userInfo info;
    // 清空脏数据
    memset(&info, 0, sizeof(info));
    info.type = 1;
    strncpy(info.name, username.c_str(), sizeof(info.name) - 1);
    strncpy(info.passwd, passwd.c_str(), sizeof(info.passwd) - 1);

    // 将信息发送到服务器
    write(sockfd, &info, sizeof(info));
#endif
    // JSON vs 结构体
    // 1、灵活和固定：
    //      JSON 的优点是灵活性。
    //      字段可以是动态的，长度也可以是可变的，不需要提前定义数据的结构。
    //      这种灵活性允许 JSON 更容易适应变化，但代价是需要付出额外的空间开销（JSON 是基于文本的格式，每个字段的名称都会随数据一起传输）
    //      结构体 则是固定的，数据的长度和结构是预先定义的，因此在传输时更加紧凑
    //      然而，这也意味着如果想要修改结构体，比如增加或删除字段，必须在发送方和接收方同时更新代码，否则可能导致解析失败。
    // 2、按需传输数据：
    //      JSON 允许只传输需要的字段。
    //      例如，如果你的结构体中包含10个字段，而实际只需要传输2个字段，JSON 只需要序列化并传输这2个字段，剩下的8个字段不会被传输，从而节省空间。
    //      结构体 是固定大小的，即使你只需要其中一部分字段，整个结构体依然会被完整地传输。
    //      这会导致空间浪费，特别是当结构体很大且只用到少量字段时，浪费会更加明显。

    // 1、创建json对象（{}：json对象）
    json_object *jsonObj = json_object_new_object();

    // 2、向json对象添加<key, value>键值对
    json_object_object_add(jsonObj, "type", json_object_new_int(REGISTER));
    json_object_object_add(jsonObj, "name", json_object_new_string(username.c_str()));
    json_object_object_add(jsonObj, "passwd", json_object_new_string(passwd.c_str()));

    // 3、将json对象转换成json字符串
    const char *jsonStr = json_object_to_json_string(jsonObj);
    cout << "jsonStr:" << jsonStr << endl;

    // 4、发送到服务器
    write(sockfd, jsonStr, strlen(jsonStr));

}

// 登录信息
void loginInfo(int sockfd)
{
    string username;
    cout << "请输入你的姓名：" << endl;
    cin >> username;

    string passwd;
    cout << "请输入你的密码：" << endl;
    cin >> passwd;

#if 0
    userInfo info;
    // 清空脏数据
    memset(&info, 0, sizeof(info));
    info.type = 2;
    strncpy(info.name, username.c_str(), sizeof(info.name) - 1);
    strncpy(info.passwd, passwd.c_str(), sizeof(info.passwd) - 1);

    // 将信息发送到服务器
    write(sockfd, &info, sizeof(info));
#endif


    // 1、创建json对象
    json_object *jsonObj = json_object_new_object();

    // 2、向json对象添加<key, value>键值对
    json_object_object_add(jsonObj, "type", json_object_new_int(LOGIN));
    json_object_object_add(jsonObj, "name", json_object_new_string(username.c_str()));
    json_object_object_add(jsonObj, "passwd", json_object_new_string(passwd.c_str()));

    // 3、将json对象转换成json字符串
    const char *jsonStr = json_object_to_json_string(jsonObj);
    cout << "jsonStr:" << jsonStr << endl;

    // 4、发送到服务器
    write(sockfd, jsonStr, strlen(jsonStr));

}

int main()
{
    // 创建socket套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket error");
        exit(-1);
    }
    cout << "sockfd:" << sockfd << endl;

    // 连接服务器
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);

    const char *serverIp = "192.168.27.129";
    inet_pton(AF_INET, serverIp, &(serverAddr.sin_addr.s_addr));

    int ret = connect(sockfd, reinterpret_cast<const sockaddr *>(&serverAddr), sizeof(serverAddr));
    if (ret != 0)
    {
        perror("connect error");
        exit(-1);
    }
    // 程序执行到这：连接服务器成功...

    // const char *str = "hello world!";
    // write(sockfd, str, strlen(str));

    signUpLoginInterFace();

    // 客户端给服务器发信息
    // string str;
    char readBuffer[BUFFER_SIZE];
    int choice = 0;

    while (1)
    {
        // 清空缓冲区
        memset(readBuffer, 0, sizeof(readBuffer));

        // cin >> str;
        // write(sockfd, str.c_str(), str.size());

        // read(sockfd, readBuffer, sizeof(readBuffer));
        // cout << "readBuffer:" << readBuffer << endl;

        cout << "请选择你想要进行的操作：";
        cin >> choice;

        switch (choice)
        {
        case 1:
            registerInfo(sockfd);
            break;
        case 2:
            loginInfo(sockfd);
            break;
        default:
            break;
        }
    }

    return 0;
}